home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 3
/
Gold Medal Software - Volume 3 (Gold Medal) (1994).iso
/
graphics
/
3dvect30.arj
/
POLY.INC
< prev
next >
Wrap
Text File
|
1993-11-18
|
62KB
|
2,089 lines
; common routines between 3d1.asm,3d2.asm and 3d3.asm
public poly_fill ; fill polygon
public clear_fill ; clear screen
public initpages ; initialize video pages selected
public flip_page ; flip between video pages
public fakeline ; draw line in memory buffer
public set_clip_absolute ; set clipping parameters - absolute
public set_clip_offset ; set clipping parameters - offset
public updvectors ; update vector positions/angles
public fastimultable ; fast imul table, dw 0-319 * 200
public clipped_line ; draw clipped line from dx,cx to ax,bx colour bp
public sort_list ; sort vector list
public drawvect ; draw vectors from command list
public look_at_it ; force camera to look at object
public calc_angles ; calculate angles between objects di,si
public calc_middle ; calculate angles of ebx,ecx,ebp into x,y
public get_displacement ; calculate difference between objects
public put_object ; put object si at ebx,ecx,ebp
public set_angle ; set object si to angle ebx,ecx,ebp
public set_shape ; set shape of object si to ax
public set_object_on ; set object si to on
public set_object_off ; guess...
public resetupd ; reset clearing limits (for clear_fill)
public move_si ; move object si to ebx,ecx,ebp in di
public twist_si ; rotate object si to ebx,ecx,ebp in di
public newfollow ; select new object for camera to follow
public where_si ; where will object si be in di frames?
public set_finall ; set xsfinal for object (location)
public set_finala ; set vxsfinal for object (angles)
public point_it ; point object si at object di
public point_dir ; point object si in direction it is moving
public point_to ; point object si at location ebx,ecx,ebp
public set_speed ; calculate velocity based on angles
public point_time ; point obj di to bx,cx,bp in di frames
public nullpalette ; only a null cross reference palette
public set_xref_palette ; set cross reference pal for object si to ebx
; clears a block from active display page
;
; this routine works only if borders of xclip land on even nybbles
; eg minimum x is 32 - works fine. but if minimum x is 37, this
; routine will clear all the way to 32 just the same. for better clearing,
; call fill_block routine with lxupdate and lyupdate parameters on stack
;
; routine was originally written by matt prichard. routine was then modified
; to clear using dwords, and clear to integer borders.
;
; entry: lxupdate+0 = left x position of area to fill
; lxupdate+2 = top y position of area to fill
; lyupdate+0 = right x position of area to fill
; lyupdate+2 = bottom y position of area to fill
align 16
clear_fill:
cmp use_clear,no
je tf_exit ; don't use clear routine
mov edi, current_page ; point to active vga page
; out_8 sc_index, map_mask ; set up for plane select, should be already set
out_8 sc_data, all_planes ; write to all planes
if usefastborders eq no
if useborders eq yes
cld ; direction flag = forward
mov ax,lxupdate+0
mov bx,lxupdate+2
mov cx,lyupdate+0
mov dx,lyupdate+2
add ax,xcent ; center on screen
add bx,xcent
add cx,ycents1
add dx,ycentp1
and ax,0fff8h
and bx,0fff8h
add bx,7
cmp ax,cliplt ; clip to inside borders
jge s tf_noclip1
mov ax,cliplt
tf_noclip1:
cmp bx,xmaxxcent
jl s tf_noclip2
mov bx,cliprt
tf_noclip2:
cmp cx,cliptp
jge s tf_noclip3
mov cx,cliptp
tf_noclip3:
cmp dx,ymaxycent
jl s tf_noclip4
mov dx,ymaxycent
tf_noclip4:
mov lxupdate+0,ax
mov lxupdate+2,bx
mov lyupdate+0,cx
mov lyupdate+2,dx
cmp ax,bx
jg tf_exit ; nothing to do!
cmp cx,dx
jg tf_exit ; nothing to do!
mov ax,cx
mov bx,dx
sub bx,ax ; get y width
mov lyupdate+2,bx ; save in ypos2
else ; if not using borders update, clear entire
mov ax,cliptp ; area!
mov bx,ymaxycent
mov cx,cliplt ; use this if you want to change the
mov lxupdate+0,cx ; clipping paramters while the program is
mov cx,cliprt ; running, and if you want to have useborders
mov lxupdate+2,cx ; = no. the alternative code to this is the
mov dx,bx ; rept code below. it is faster but takes
sub dx,ax ; more memory.
mov lyupdate+2,dx
endif
movzx esi,ax
movzx eax,w [esi*2+fastimultable] ; mul y1 by bytes per line
add edi,eax ; di = start of line y1
mov dx,lxupdate ; dx = x1 (pixel position)
shr dx,2 ; dx/4 = bytes into line
movzx edx,dx
add edi,edx ; di = addr of upper-left corner
mov cx,lxupdate+2 ; cx = x2 (pixel position)
sub cx,lxupdate
shr cx,3 ; cx/4 = bytes into line
inc cx
; di = addr of upper left block to fill
; cx = # of bands to fill in (width)
mov dx,xactual/4 ; dx = di increment
sub dx,cx ; = screen_width-# planes filled
sub dx,cx
movzx ecx,cx
mov ebx,ecx ; bx = quick refill for cx
mov si,lyupdate+2 ; si = # of lines to fill
mov ax,background ; get fill color
push ax ; make 32 bit
shl eax,16
pop ax
shr ecx,1
shr ebx,1
jnc s tf_middle_loop2
align 4
tf_middle_loop1:
stosw
rep stosd ; fill in entire line
mov ecx, ebx ; recharge cx (line width)
add edi, edx ; point to start of next line
loopx si, tf_middle_loop1 ; loop until all lines drawn
ret
align 16
tf_middle_loop2:
rep stosd ; fill in entire line, doubleword store
mov ecx, ebx ; recharge cx (line width)
add edi, edx ; point to start of next line
loopx si, tf_middle_loop2 ; loop until all lines drawn
tf_exit:
ret ; exit
; this rept code generates a huge program that wipes the screen FAST
; only use this if you don't want to change the clipping parameters while
; the program is running.
else ; if useborders = no, clear entire area
mov ax,background ; get fill color
shl eax,16 ; make 32 bit
mov ax,background
i=0 ; this is a huge but fast method
rept (ymax-ymin)
j=0
rept (xmax-xmin)/4/4
mov d [j+xactual/4*(ycenter+ymin)+(xcenter+xmin)/4+xactual/4*i+edi],eax
j=j+4
endm
if (xmax-xmin)/4/4 ne (xmax+8-xmin)/4/4
mov w [j+xactual/4*(ycenter+ymin)+(xcenter+xmin)/4+xactual/4*i+edi],ax
endif
i=i+1
endm
tf_exit:
ret
endif
; fill starting at oney, from firstbyte to lastbyte
align 16
pf_done:
pop eax
pf_outearly:
mov oney,1000 ; reset for next polygon call
ret
align 16
poly_fill:
; out_8 sc_index, map_mask ; set up for plane select
xor eax,eax
mov bx,oney ; ax=y1
cmp bx,ymins
jl s pf_missub
cmp bx,ymaxs
jge pf_outearly
sub bx,ymins
mov ax,bx
pf_missub:
if usesteel eq yes
cmp steel,0 ; test to use steel texture
jl s pf_skipsteel
mov bl,colq ; yes, save colour offset and 16 block
mov steelc,bl
and steelc,0f0h ; save base offset of 16 colour block
shl bl,2 ; colour offset is *2 (small) *4 (large)
add bl,al ; make steel always constant
and bl,03fh ; colour indexer (so sides look different)
mov steel ,bl
pf_skipsteel:
endif
mov ebp,eax ; indexer to line
shl bp,1
add ax, cliptp
mov edi, current_page ; point to active vga page
mov esi,eax
mov ax,w [esi*2+fastimultable] ; mul y1 by bytes per line
add edi,eax ; di = start of line y1
xor edx,edx
pf_more_lines:
push edi ; save right hand position
mov ax, [firstbyte+ebp]
cmp ax,xmaxs ; check if fill done
jge pf_done
xor ebx,ebx
if usesteel eq yes
mov bl,steel ; use steel texture?
or bl,bl
jl s pf_no_steel
mov dl,pf_updown[ebx]
add dl,steelc
mov colq,dl
inc bl
and bl,03fh ; 16 colours, 32 positions for steel texture
mov steel,bl
pf_no_steel:
endif
mov bx,[lastbyte+ebp]
add ax,xcent
add bx,xcent
mov dx,ax ; dx = x1 (pixel position)
shr dx,2 ; dx/4 = bytes into line
add edi,edx ; di = addr of upper-left corner
mov ecx,ebx ; cx = x2 (pixel position)
shr cx,2 ; cx/4 = bytes into line
cmp dx,cx ; start and end in same band?
jg pf_exit ; skip if fakeline fails connection
je pf_one_band_only ; if so, then special processing
mov ah,colq ; get fill color
sub cx,dx ; cx = # bands -1
mov si,ax ; si = plane#(x1)
and esi,plane_bits ; if left edge is aligned then
jz s pf_l_plane_flush ; no special processing..
; draw "left edge" of 1-3 pixels...
out_8 sc_data, left_clip_mask[esi] ; set left edge plane mask
mov [edi], ah ; fill in left edge pixels
inc edi ; point to middle (or right) block
dec cx ; reset cx instead of jmp pf_right
pf_l_plane_flush:
inc cx ; add in left band to middle block
; di = addr of 1st middle pixel (band) to fill
; cx = # of bands to fill -1
pf_right:
mov si,bx ; get xpos2
and si,plane_bits ; get plane values
cmp si,0003 ; plane = 3?
je s pf_r_edge_flush ; hey, add to middle
; draw "right edge" of 1-3 pixels...
out_8 sc_data, right_clip_mask[esi] ; right edge plane mask
mov esi,edi ; get addr of left edge
add esi,ecx ; add width-1 (bands)
dec esi ; to point to top of right edge
pf_right_loop:
mov [esi], ah ; fill in right edge pixels
dec cx ; minus 1 for middle bands
jz s pf_exit ; uh.. no middle bands...
pf_r_edge_flush:
; di = addr of upper left block to fill
; cx = # of bands to fill in (width)
out_8 sc_data, all_planes ; write to all planes
mov dx, xactual/4 ; dx = di increment
sub dx, cx ; = screen_width-# planes filled
mov al, ah ; colour is in high and low for stosw
pf_middle_loop:
shr cx,1 ; use doubleword transfer
jnc s pf_ord
stosb ; if cx odd, store byte first
pf_ord:
rep stosw ; don't use stosd
pf_exit:
pop edi
mov [firstbyte+ebp],1000 ; reset table for next polygon
mov [lastbyte+ebp],-1000
add bp,2
add edi,xactual/4
jmp pf_more_lines
pf_one_band_only:
cmp ax, cliplt
jne s pf_nexit
cmp bx,ax
je s pf_exit
pf_nexit:
cmp ax, cliprt
je s pf_exit
mov si,ax ; get left clip mask, save x1
and esi,plane_bits ; mask out row #
mov al,left_clip_mask[esi] ; get left edge mask
mov si,bx ; get right clip mask, save x2
and si,plane_bits ; mask out row #
and al,right_clip_mask[esi] ; get right edge mask byte
out_8 sc_data, al ; clip for left & right masks
mov ah,colq ; get fill color
mov [edi], ah ; fill in pixels
jmp s pf_exit ; outa here, for this line
; small steel texture, make sure to set shl bl,*1* before skip_steel:
;pf_updown db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
; db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
; db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
; db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
; large steel texture, make sure to set shl bl,*2* before skip_steel:
pf_updown db 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9
db 10,10,11,11,12,12,13,13,14,14,15,15
db 15,15,14,14,13,13,12,12,11,11,10,10
db 9,9,8,8,7,7,6,6,5,5,4,4,3,3,2,2,1,1,0,0
fastimultable label word
i=0
rept yactual
dw i*(xactual/4)
i=i+1
endm
resetupd: ; make old update equal current update
if useborders eq yes
mov ax,xupdate[0] ; and reset current update
mov lxupdate[0],ax
mov ax,xupdate[2]
mov lxupdate[2],ax
mov ax,yupdate[0]
mov lyupdate[0],ax
mov ax,yupdate[2]
mov lyupdate[2],ax
mov ax,xmaxs
mov bx,xmins1
mov cx,ymaxs
mov dx,ymins1
mov xupdate[0],ax
mov xupdate[2],bx
mov yupdate[0],cx
mov yupdate[2],dx
endif
ret
; hey! where is my postcard! see readme.doc file and send me that postcard!
initpages:
pushw 0
call set_display_page
pushw 0
call set_active_page
pushw 0
call clear_vga_screen
pushw 1
call set_active_page
pushw 0
call clear_vga_screen
ret
flip_page:
if not pages eq 1
mov ax,display_page
xor al,1
push ax
call set_display_page
mov ax,active_page
xor al,1
push ax
call set_active_page
else
call sync_display
display "Note: Page flipping not allowed with only 1 page"
display " See equ.inc to select a mode with more than 1 page"
endif
ret
; draw a line in tables firstbyte,lastbyte
;
; line is not drawn on screen but is drawn in memory tables. to use,
; tables must be clear, (default is always clear), just draw
; line around screen, in any order, then call poly_fill. the polygon will
; be drawn and checked in memory, then poly_fill will plop it on the current
; page. poly_fill routine clears tables during plot so tables are ready for
; more lines and more polygons.
align 16
fakeline:
mov ax,y1
cmp y2,ax ; flip order of points if drawing up
jg s okorder
mov bx,x1
xchg bx,x2
xchg bx,x1
xchg ax,y2
mov y1,ax
okorder:
cmp ax,oney
jge s nonewoney
mov oney,ax
nonewoney:
if useborders eq yes
cmp ax,yupdate+0 ; update borders for clearing routine
jge s up_no1
mov yupdate+0,ax
up_no1:
mov ax,y2
cmp ax,yupdate+2
jng s up_no2
mov yupdate+2,ax
up_no2:
mov dx,xupdate+0
mov cx,xupdate+2
mov ax,x1
mov bx,x2
cmp ax,dx
jge s up_no3
dec ax
mov xupdate+0,ax
mov dx,ax
inc ax
up_no3:
cmp bx,cx
jle s up_no4
inc bx
mov xupdate+2,bx
mov cx,bx
dec bx
up_no4:
cmp bx,dx
jge s up_no5
dec bx
mov xupdate+0,bx
up_no5:
cmp ax,cx
jle s up_no6
inc ax
mov xupdate+2,ax
up_no6:
endif
mov ax,x2 ; ax=x
sub ax,x1
mov bx,y2 ; bx=y
sub bx,y1
jle sliver
mov rise,bx
movsx ebx,bx
shl eax,16
cdq
idiv ebx
mov ebp,eax ; ebp = slope*65536 (allows decimals)
mov ax,ymins
cmp y1,ax ; check if above screen
jge s li_abov1
sub ax,y1 ; ax = abs(difference of ymin-y1)
sub rise,ax ; dec counter
jle li_out ; line totally off screen
movsx eax,ax ; prepare for 32bit mul
imul ebp
shr eax,16 ; get top word
add x1,ax ; set new x1,y1 pair
mov ax,ymins
mov y1,ax
li_abov1:
movsx edx,x1
shl edx,16
mov cx,rise
mov ax,y1
movzx ebx,ax ; bx pointer first/lastbyte table
sub bx,ymins
shl bx,1 ; bx now word
add ax,cx ; will line go off bottom of screen?
cmp ax,ymaxs
jl s linep ; no...
sub ax,ymaxs ; yes, truncate cx for early exit
sub cx,ax
jle s li_out ; right off screen
linep:
mov eax,edx
movzx ecx,cx
mov di,xmins
mov si,xmaxs1
align 16
lineloop:
shr edx,16 ; main line drawing loop!!!
cmp dx,di
jg s nou
mov dx,di
nou:
cmp dx,si
jl s noq
mov dx,si
noq:
cmp dx,firstbyte[ebx] ; fix first and lastbyte table
jge s ci1
mov firstbyte[ebx],dx
ci1:
cmp dx,lastbyte[ebx]
jng s ci2
mov lastbyte[ebx],dx
ci2:
add eax,ebp
mov edx,eax
add bx,2
loop s lineloop
li_out:
ret
align 16
sliver:
movzx ebx,y1 ; bx pointer first/lastbyte table
cmp bx,ymaxs
jge li_out
cmp bx,ymins ; clip to borders
jl li_out
sub bx,ymins
shl ebx,1 ; ebx now word
mov cx,x1
cmp cx,xmins
jge s nouq1
mov cx,xmins
nouq1:
cmp cx,xmaxs
jl s noqq1
mov cx,xmaxs1
noqq1:
cmp cx,firstbyte[ebx] ; fix first and lastbyte table
jg s ci1q1
mov firstbyte[ebx],cx
ci1q1:
cmp cx,lastbyte[ebx]
jng s ci6q1
mov lastbyte[ebx],cx
ci6q1:
mov cx,x2
cmp cx,xmins
jge s nouq2
mov cx,xmins
nouq2:
cmp cx,xmaxs
jl s noqq2
mov cx,xmaxs1
noqq2:
cmp cx,firstbyte[ebx] ; fix first and lastbyte table
jg s ci1q2
mov firstbyte[ebx],cx
ci1q2:
cmp cx,lastbyte[ebx]
jng s ci6q
mov lastbyte[ebx],cx
ci6q:
ret
db " ---- Hey, What are you doing ripping my code?! ---- "
; set new clipping parameters where center is in middle of points ax,bx cx,dx
; where points are absolutes! eg (10,10) (50,50) would be a small window in
; the top corner of the screen.
set_clip_absolute:
mov si,cx ; calc center based on points
sub si,ax
shr si,1
add si,ax
mov di,dx
sub di,bx
shr di,1
add di,bx
sub ax,si ; now make points offset from center
sub cx,si
sub bx,di
sub dx,di
; set new clipping parameters. does all pre-calculation for variables and
; resets oney, firstbyte and lastbyte table. si,di is center of screen. ax,bx
; and cx,dx are topleft and botright points to clip to. clipping will include
; minimum clip variables but will exclude maximum clip variables. eg -160,-100
; +160,+100, with center 160,100 are valid clip parameters. points are offsets
; from center, not absolutes! this allows you to have the camera looking to the
; left or right of where the pilot/plane is moving without having to change
; the camera angle. note: this can only change slightly as distortion occures
; with too large an offset. make sure to assemble the original file with the
; maximum y size you will ever need so tables are set to correct size.
set_clip_offset:
mov bp,dx
sub bp,bx
cmp bp,ymax-ymin ; check input parameters with assembley restraints
jg you_must_assemble_original_file_with_larger_clipping_parameters_to_achieve_this
mov xmins,ax
mov xmaxs,cx
mov ymins,bx
mov ymaxs,dx
mov xcent,si
mov ycent,di
mov cliptp,di
add cliptp,bx
mov ycentp1,di
inc ycentp1
mov ycents1,di
dec ycents1
mov clipbt,di
add clipbt,dx
dec clipbt
mov cliplt,si
add cliplt,ax
mov cliprt,si
add cliprt,cx
dec cliprt
mov xmaxxcent,si
add xmaxxcent,cx
mov ymaxycent,di
add ymaxycent,dx
mov xmins1,ax
dec xmins1
mov xmaxs1,cx
dec xmaxs1
mov ymins1,bx
dec ymins1
mov ymaxs1,dx
dec ymaxs1
movsx eax,ax
movsx ebx,bx
movsx ecx,cx
movsx edx,dx
mov xmit,eax
mov xmat,ecx
mov ymit,ebx
mov ymat,edx
sub xmit,tolerance
add xmat,tolerance
sub ymit,tolerance
add ymat,tolerance
you_must_assemble_original_file_with_larger_clipping_parameters_to_achieve_this:
ret
align 16
; update vector list based on traces_past
; i could have used a loop but shl ax,cl works faster
;
; what i am really doing is:
;
; for i = 1 to traces_past
; call updvectors
; next i
;
; but instead i am shifting and adding (if bit present) for a faster method
; you get the idea right?
;
; this way, the slower the machine, the faster we move the objects to
; maintain a universal speed from 486dx66 machine to 386sx25 machine
updvectors:
mov bx, traces_past
mov bp,bx
mov traces_past,0
mov dx,1
xor cl,cl
up_loop:
shr bl,1
jnc not_call
call updvectors2
not_call:
shl dx,1 ; dx = 1,2,4,8..
add cl,1 ; cx = 0,1,2,3,4,5,6...
or bl,bl ; all bits clear?
jne up_loop
cmp wfollow,no ; check if camera has reached follow object
je s nretest ; nothing to follow
cmp eyeacount,0
jne s nretest ; not reached yet
mov si,wfollow ; looking at it, re-call newfollow
mov di,oldspeed
cmp di,bp
ja newfollow ; re-calculate in case its accelerating
jmp just_look_at_it_now_instead_of_calculating
nretest:
ret
align 16
updvectors2: ; update vector list - shifted by cl
; and dec'ed by dx
i=0
rept maxobjects+1 ; generate unrolled update loop
local nupang, nuploc, nuder, nuuder
cmp acount+i*2,0
je nupang
sub acount+i*2,dx
ja nuder
mov acount+i*2,0 ; counter has expired with decimals!, now
mov ax,vxsfinal+i*2 ; use final position!
mov vxs+i*2,ax
mov ax,vysfinal+i*2
mov vys+i*2,ax
mov ax,vzsfinal+i*2
mov vzs+i*2,ax
jmp nupang ; outa here
align 16
nuuder:
mov lcount+i*2,0
mov eax,xsfinal+i*4 ; linear counter has expired with carry!
mov xs+i*4,eax
mov eax,ysfinal+i*4
mov ys+i*4,eax
mov eax,zsfinal+i*4
mov zs+i*4,eax
jmp nuploc
align 16
nuder:
mov ax,vxadds+i*2 ; update angles
shl ax,cl
add ax,vxs+i*2
mov vxs+i*2,ax
mov ax,vyadds+i*2
shl ax,cl
add ax,vys+i*2
mov vys+i*2,ax
mov ax,vzadds+i*2
shl ax,cl
add ax,vzs+i*2
mov vzs+i*2,ax
nupang:
cmp lcount+i*2,0
je nuploc
sub lcount+i*2,dx
jna nuuder ; go backward to avoid instruction buffer flush
mov eax,xadds+i*4 ; update position
shl eax,cl
add eax,xs+i*4
mov xs+i*4,eax
mov eax,yadds+i*4
shl eax,cl
add eax,ys+i*4
mov ys+i*4,eax
mov eax,zadds+i*4
shl eax,cl
add eax,zs+i*4
mov zs+i*4,eax
nuploc:
i=i+1
endm
ret
align 16
put_object:
movzx esi,si
mov xs[esi*4],ebx
mov ys[esi*4],ecx
mov zs[esi*4],ebp
ret
align 16
set_angle:
movzx esi,si
mov vxs[esi*2],bx
mov vys[esi*2],cx
mov vzs[esi*2],bp
ret
align 16
set_shape:
movzx esi,si
mov whatshape[esi*2],ax
ret
align 16
set_object_on:
movzx esi,si
mov onoff[esi],1
ret
align 16
set_object_off:
movzx esi,si
mov onoff[esi],0
ret
; move object si from wherever it is now to ebx,ecx,ebp in di frames
; move is 32 bit, make sure high words of registers are set!
; time to get there is 16 bit. (if you need more, think! 65535 frames at
; 1/30 frames a sec is 36 minutes!)
align 16
move_si:
movzx esi,si
shl si,2 ; si = dword
mov xsfinal[esi],ebx
mov ysfinal[esi],ecx
mov zsfinal[esi],ebp
sub ebx,xs[esi]
sub ecx,ys[esi]
sub ebp,zs[esi]
movzx edi,di
mov eax,ebx ; 32 bit moves
cdq
idiv edi
mov xadds[esi],eax
mov eax,ecx
cdq
idiv edi
mov yadds[esi],eax
mov eax,ebp
cdq
idiv edi
mov zadds[esi],eax
shr si,1 ; si = word
mov lcount[esi],di
shr si,1 ; restore original si
ret
align 16
; rotate object si from wherever it is now to ebx,ecx,ebp in di frames
; rotate is 32 bit, make sure high words of registers are set!
; time to get there is 16 bit. note: although resulting angle will be
; 16 bit, input angle is 32 bit!. this allows you to rotate many times
; before coming to rest at a specified angle and also allows you to
; specify the direction of rotation. di specifies time to arrive.
; final location is absolute, not relative to current angle.
; eg 00000100 is "rotate forwards until 100 degrees"
; 00078000 is "rotate 7 full rotations and come to rest at 32768 degrees"
; fffd9000 is "rotate backwards 2 rotations and come to rest at 9000h degrees"
; fffffff0 is "rotate backwards until 65520 degrees (-16)"
; therefore, to reverse the direction of rotation (but maintain the final
; position) xor ebx,0ffff0000h (or ecx or ebp). ax is final position, but
; top word of eax determines direction and number of turn to get there.
twist_si:
movzx esi,si
shl si,1 ; si = word
mov vxsfinal[esi],bx ; set final position when acount becomes 0
mov vysfinal[esi],cx
mov vzsfinal[esi],bp
movzx eax,vxs[esi]
sub ebx,eax
movzx eax,vys[esi]
sub ecx,eax
movzx eax,vzs[esi]
sub ebp,eax
movzx edi,di
mov eax,ebx ; 32 bit rotate
cdq
idiv edi
mov vxadds[esi],ax
mov eax,ecx
cdq
idiv edi
mov vyadds[esi],ax
mov eax,ebp
cdq
idiv edi
mov vzadds[esi],ax
mov acount[esi],di
shr si,1 ; restore original si
ret
align 16
look_at_it: ; force camera to look at object wherelook
mov si,wherelook
cmp si,no
je s noat ; get out, no object to look at (-1=flag)
mov edi,cameraobject
movzx esi,si
call calc_angles ; calculate difference between camera and obj
mov eyeay,bx ; this is where the camera should look...
mov eyeax,ax
noat:
ret
; calculate angles between objects esi and edi. angles are from point of view
; of di.
align 16
calc_angles:
call get_displacement
calc_middle:
push ecx ebx ebp
mov ecx,ebx ; first get z,x plane, (y angle)
mov eax,ebp
or eax,eax
je lk_right_above ; check arctan(cx/0)
call arctan
lk_resume:
mov dsq,ax ; save y angle
call cosign ; set up 32bit sin/cos multipliers
mov vycos,eax
mov ax,dsq
call sign
pop ebp ebx ; now compute sqr(z^2+x^2) through y rotation
imul ebx ; use angle from calculation above
shrd eax,edx,14
mov edi,eax
mov eax,vycos
imul ebp
shrd eax,edx,14
add eax,edi ; di = new z = run
pop ecx ; cx = rise
or eax,eax
je s noaq
call arctan ; get ax=arctan(y/sqr(z^2+x^2))
mov bx,dsq ; bx = y angle , ax = x angle
noaq:
ret
align 16
lk_right_above:
mov ax,vys[esi] ; camera directly above object, use old y
jmp lk_resume
align 16
get_displacement:
movzx esi,si ; in case user is lazy
movzx edi,di
mov ebx,xs[esi*4] ; get displacement of esi to edi
sub ebx,xs[edi*4]
mov ecx,ys[esi*4]
sub ecx,ys[edi*4]
mov ebp,zs[esi*4]
sub ebp,zs[edi*4]
ret
align 16
; new follow, si = object for new follow, di = time to get there.
newfollow:
mov wfollow,si ; save in case object is accelerating
mov oldspeed,di
mov wherelook,no ; disable look_at_si routine
call where_si ; figure out where object si will end up
mov di,oldspeed ; figure out where camera will end up
mov ax,eyelcount
cmp ax,di ; if di>lcount, shorten to lcount
ja s tx
mov di,ax
tx:
movzx edi,di
mov eax,eyexadds
imul edi ; figure out where camera will be di*frames
add eax,eyex
sub ebx,eax ; get displacement to eye
mov eax,eyeyadds
imul edi
add eax,eyey
sub ecx,eax
mov eax,eyezadds
imul edi
add eax,eyez
sub ebp,eax
call calc_middle ; jump in middle of angle computation
mov eyefinalax,ax
mov eyefinalay,bx
mov di,bx
sub ax,eyeax ; get difference from where we are now
sub di,eyeay
add ax,followtol ; check if already looking at it
cmp ax,followtol*2
ja s calcit
add di,followtol
cmp di,followtol*2
jb just_look_at_it_now_instead_of_calculating
sub di,followtol
calcit:
sub ax,followtol
mov si,oldspeed ; ax=x angle, di=y angle, si=# frames
cwd
push dx ; save sign extend
idiv si ; x/time
pop dx
or ax,ax
jne s n0
shl dx,1
mov ax,dx
inc ax ; ax = 1 or ax = -1
n0:
mov eyevxadds,ax
mov ax,di
cwd
push dx
idiv si ; y/time
pop dx
or ax,ax ; check if zero slope, must have some...
jne s n1
shl dx,1 ; dx = fffe (-2) or 0
mov ax,dx
inc ax ; ax = 1 or ax = -1
n1:
mov eyevyadds,ax
mov eyeacount,si
shr oldspeed,1 ; if need to try again, time/2
mov ax,eyevzadds ; now adjust any z rotation into finalz
imul si
add ax,eyeaz
mov eyefinalaz,ax
ret
align 16
just_look_at_it_now_instead_of_calculating:
mov ax,wfollow
mov wherelook,ax ; already looking at object, now follow it
mov wfollow,no
ret
align 16
; figure out where object si will be in di frames.
where_si:
movzx esi,si
mov ax,lcount[esi*2]
or ax,ax
jne s nx
mov ebx,xs[esi*4] ; if object has no velocity, xs is position
mov ecx,ys[esi*4]
mov ebp,zs[esi*4]
ret
nx:
cmp ax,di ; if di>lcount, shorten to lcount
ja s nxq
mov di,ax
nxq:
movzx edi,di
mov eax,xadds[esi*4] ; figure out where object will be di*frames
imul edi
add eax,xs[esi*4]
mov ebx,eax
mov eax,yadds[esi*4]
imul edi
add eax,ys[esi*4]
mov ecx,eax
mov eax,zadds[esi*4]
imul edi
add eax,zs[esi*4]
mov ebp,eax
ret
align 16
; draw vectors from sides list.
; number of "sides" is "showing"
dv_none2:
ret
drawvect:
cmp showing,0 ; no sides visible?
je s dv_none2
mov whichside,0 ; start at side 0
movzx ebp,order[0] ; indexer to sides
dv_loop2:
test textures[ebp],line+himap+point ; test if line, point, scalable bitmap or bitmapped texture
jnz dv_testit ; yes, do faster line routine
shl bp,mult
mov dx,sides[ebp] ; first point is end flag
dv_loop1:
movzx esi,sides[ebp] ; get point, shl 1 not needed, pre-shl'ed
mov ax,[xp+esi]
mov bx,[yp+esi]
mov x1,ax
mov y1,bx
mov si,[sides+ebp+2] ; get next point
cmp si,dx ; test if last = first, therefore done
pushf
mov ax,[xp+esi]
mov bx,[yp+esi]
mov x2,ax
mov y2,bx
push ebp dx
call fakeline ; draw next line
pop dx ebp
add bp,2 ; bump to next pointer now
popf ; was this point equal to the first point?
jne s dv_loop1 ; no, draw more lines
movzx esi,whichside ; set colour for this side
mov si,order[esi]
mov ebx,palxref ; get offset of palette cross reference table for this object
mov al,b surfcolors[esi]
xlat
mov colq,al
mov bx,textures[esi] ; use register which we can access low byte
and bl,wavey ; strip steel command bit
sub bl,wavey
mov steel,bl
call poly_fill
dv_return:
add whichside,2 ; bump bp to next block of points
movzx ebp,whichside
mov bp,order[ebp] ; get sort order
dec showing ; count for all sides
jne dv_loop2
dv_none:
ret
align 16
dv_testit:
mov ax,textures[ebp] ; perform command, return to dv_return
test al,line
jnz dv_doline
test al,point
jnz dv_dopoint
; draw bitmap at location x,y,z if userotate = 32 or command = 32
shl bp,mult
push ax ebp
movzx ebx,[sides+4+ebp]
movzx ecx,[sides+6+ebp]
movzx esi,[sides+2+ebp]
shl si,2 ; si = dword
add ebx,bitx[esi]
add ecx,bity[esi] ; ebx,ecx = top corner of bitmap in 3d
mov eax,bitbase[esi]
mov bitmap,eax
mov si,[sides+0+ebp]
mov bp,[zp+esi]
call make3d ; ebx,ecx = difference from center
pop ebp
movzx esi,[sides+0+ebp] ; get point
mov ax,[xp+esi]
mov bp,[yp+esi]
sub ax,bx ; bx = x width/2 ax, bp = top corner
sub bp,cx ; cx = y height/2
if useborders eq yes
cmp bp,yupdate+0
jge s up_nq12
mov yupdate+0,bp
up_nq12:
cmp ax,xupdate+0
jge s up_nq32
mov xupdate+0,ax
up_nq32:
mov di,ax
mov dx,bp
endif
add ax,xcent
add bp,ycent
mov destx,ax
mov desty,bp
shl bx,1
shl cx,1
mov destwidth,bx
mov destheight,cx
if useborders eq yes
add di,bx
add dx,cx
cmp dx,yupdate+2
jng s up_nq42
mov yupdate+2,dx
up_nq42:
cmp di,xupdate+2
jng s up_nq22
mov xupdate+2,di
up_nq22:
endif
pop ax
test al,lomap-himap ; test to use 1/4 scale bitmap or full scale
jz s noq19
call xscale4
jmp dv_return
align 16
noq19:
call xscale2
noq7:
jmp dv_return
align 16
dv_dopoint:
mov dx,surfcolors[ebp] ; get colour of point
shl bp,mult
movzx esi,[sides+ebp] ; get point x,y
mov bx,[xp+esi]
mov cx,[yp+esi]
cmp bx,xmins ; check if on screen
jl s noq7
cmp bx,xmaxs
jge s noq7
cmp cx,ymins
jl s noq7
cmp cx,ymaxs ; ymaxs1 if larger pixel
jge s noq7
mov edi, current_page ; point to active vga page
if useborders eq yes
cmp cx,yupdate+0
jge s up_no16
mov yupdate+0,cx
up_no16:
cmp bx,xupdate+0
jge s up_no36
mov xupdate+0,bx
up_no36:
cmp cx,yupdate+2
jng s up_no46
mov yupdate+2,cx
up_no46:
cmp bx,xupdate+2
jng s up_no26
mov xupdate+2,bx
up_no26:
endif
add bx,xcent
add cx,ycent
mov bp,dx ; save colour
mov si,cx
mov ax,[esi*2+fastimultable] ; get offset to start of line
mov cx, bx ; copy to extract plane # from
shr bx, 2 ; x offset (bytes) = xpos/4
add bx, ax ; offset = width*ypos + xpos/4
mov ax, map_mask_plane1 ; map mask & plane select register
and cl, plane_bits ; get plane bits
shl ah, cl ; get plane select value
out_16 sc_index, ax ; select plane
movzx ebx,bx
mov ax,bp ; re-get colour
mov [edi+ebx],al ; draw pixel, low is top, high is bottom
; add edi,xactual/4
; mov [edi+ebx],ah ; draw larger bullet/pixel (high byte)
; if drawing larger pixel, change above code to this!
; cmp cx,ymaxs1
; jge s noa7
jmp dv_return
align 16
; handle line command from drawvect, uses clipped_line routine
dv_doline:
mov edi,ebp ; save...
mov ebx,palxref ; get offset of palette cross reference table for this object
movzx ecx,b surfcolors[ebp]
movzx bp,b [ecx+ebx]
shl di,mult
movzx esi,[sides+edi] ; get first point
mov dx,[xp+esi]
mov cx,[yp+esi]
mov si,[sides+edi+2] ; second point indexer
mov ax,[xp+esi] ; now load up second point
mov bx,[yp+esi]
call clipped_line
jmp dv_return ; return to drawvect
; draw clipped line in cartesian format (0,0 is screen center)
; similar routine to fakeline but faster, more accurate and draws directly
; to screen (current_page). updates clearing borders (if used)
;
; draws line from (dx,cx) to (ax,bx) using colour bp
;
clipped_line:
cmp bx,cx ; flip order of points if drawing up
jg s r_okorder
xchg bx,cx
xchg ax,dx
r_okorder:
mov x1,dx
mov y1,cx
mov x2,ax
mov y2,bx
if useborders eq yes
cmp cx,yupdate+0 ; update borders for clearing routine
jg s r_up_no1
mov yupdate+0,cx
r_up_no1:
cmp bx,yupdate+2
jng s r_up_no2
mov yupdate+2,bx
r_up_no2:
mov bx,ax
mov ax,dx
mov dx,xupdate+0
mov cx,xupdate+2
cmp ax,dx
jge s r_up_no3
dec ax
mov xupdate+0,ax
mov dx,ax
inc ax
r_up_no3:
cmp bx,cx
jle s r_up_no4
inc bx
mov xupdate+2,bx
mov cx,bx
dec bx
r_up_no4:
cmp bx,dx
jge s r_up_no5
dec bx
mov xupdate+0,bx
r_up_no5:
cmp ax,cx
jle s r_up_no6
inc ax
mov xupdate+2,ax
r_up_no6:
mov ax,x2 ; ax=x
sub ax,x1
mov bx,y2 ; bx=y
sub bx,y1
elseif not useborders eq yes
sub ax,dx
sub bx,cx
endif
mov dx,bp
mov colq,dl
mov dx,ymaxs
cmp y1,dx
jge cl_return
mov rise,bx
movsx ebx,bx
or ebx,ebx
jne s r_nsliver
mov bx, y1
cmp bx, ymins ; draw sliver, avoid divide by zero
jl cl_return
cmp bx, dx ; dx = ymax
jge cl_return
add bx,ycent
movzx esi,bx
movzx eax,[esi*2+fastimultable] ; get offset to start of line
mov edi, current_page
add edi, eax ; edi = starting y location
mov rise,1
mov dx, x1 ; from here...
mov si, x2 ; ..to here
cmp si,xmins
jge s u_nou3
mov si,xmins
u_nou3:
cmp si,xmaxs
jl s u_noq3
mov si,xmaxs1
u_noq3:
jmp r_splint ; re-enter draw later in code
align 16
r_nsliver:
shl eax,16
cdq
idiv ebx
mov ebp,eax ; ebp = slope*65536 (allows decimals)
mov ax,ymins
cmp y1,ax ; check if above screen
jge s r_li_abov1
sub ax,y1 ; ax = abs(difference of ymin-y1)
sub rise,ax ; dec counter
jle cl_return ; line totally off screen
movsx eax,ax ; prepare for 32bit mul
imul ebp
shr eax,16 ; get top word
add x1,ax ; set new x1,y1 pair
mov ax,ymins
mov y1,ax
r_li_abov1:
mov bx,y1 ; bx distance from top of screen
add bx,ycent
movzx esi,bx ; calculate screen address
movzx eax,[esi*2+fastimultable] ; get offset to start of line
mov edi, current_page
add edi,eax ; edi = starting y location
movsx edx,x1
shl edx,16
mov cx,rise
mov ax,y1
add ax,cx ; will line go off bottom of screen?
cmp ax,ymaxs
jl s r_linep ; no...
sub ax,ymaxs ; yes, truncate cx for early exit
sub rise,ax
jle cl_return
r_linep:
mov eax,edx
movzx ecx,cx
mov esi,edx
shr esi,16
cmp si,xmins
jge s r_nou
mov si,xmins
r_nou:
cmp si,xmaxs
jl s r_noq
mov si,xmaxs1
align 16
r_noq:
r_lineloop:
add eax,ebp ; main line drawing loop!!! (for lines)
mov edx,eax
shr edx,16
r_splint:
cmp dx,xmins
jge s u_nou
mov dx,xmins
cmp dx,si
je r_mis
u_nou:
cmp dx,xmaxs
jl s u_noq
mov dx,xmaxs1
cmp dx,si
je r_mis
u_noq:
push dx edi ebp eax ; save for next line
cmp dx,si
jle s r_no_switch
xchg dx,si
r_no_switch:
add dx,xcent
add si,xcent
mov ax,dx
mov bx,si
mov x2,si
shr dx,2 ; dx/4 = bytes into line
movzx edx,dx
add edi,edx ; di = addr of upper-left corner
movzx ecx,bx ; cx = x2 (pixel position)
shr cx,2 ; cx/4 = bytes into line
cmp dx,cx ; start and end in same band?
je rf_one_band_only ; if so, then special processing
sub cx,dx ; cx = # bands -1
movzx esi,ax ; si = plane#(x1)
and si,plane_bits ; if left edge is aligned then
jz s rf_l_plane_flush ; no special processing..
; draw "left edge" of 1-3 pixels...
out_8 sc_data, left_clip_mask[esi] ; set left edge plane mask
mov al,colq ; get fill color
mov [edi], al ; fill in left edge pixels
inc edi ; point to middle (or right) block
dec cx ; reset cx instead of jmp s rf_right
rf_l_plane_flush:
inc cx ; add in left band to middle block
; di = addr of 1st middle pixel (band) to fill
; cx = # of bands to fill -1
rf_right:
movzx esi,bx ; get xpos2
and si,plane_bits ; get plane values
cmp si,0003 ; plane = 3?
je s rf_r_edge_flush ; hey, add to middle
; draw "right edge" of 1-3 pixels...
out_8 sc_data, right_clip_mask[esi] ; right edge plane mask
mov esi,edi ; get addr of left edge
add esi,ecx ; add width-1 (bands)
dec esi ; to point to top of right edge
mov al,colq ; get fill color
rf_right_loop:
mov [esi], al ; fill in right edge pixels
dec cx ; minus 1 for middle bands
jz s rf_exit ; uh.. no middle bands...
rf_r_edge_flush:
; di = addr of upper left block to fill
; cx = # of bands to fill in (width)
out_8 sc_data, all_planes ; write to all planes
mov dx, xactual/4 ; dx = di increment
sub dx, cx ; = screen_width-# planes filled
mov al, colq ; get fill color
mov ah, al ; colour is in high and low for stosw
push ax ; make colour 32 bit
shl eax,16
pop ax
rf_middle_loop:
shr cx,1 ; use doubleword transfer
jnc s rf_ord
stosb ; if cx odd, store byte first
jcxz s rf_exit ; no words after stosb
rf_ord:
shr cx,1
jnc rf_dord
stosw
jcxz s rf_exit ; no doublewords after stosw
rf_dord:
rep stosd ; fill in entire line
jmp s rf_exit ; outa here, for this line
rf_one_band_only:
movzx esi,ax ; get left clip mask, save x1
and si,plane_bits ; mask out row #
mov al,left_clip_mask[esi] ; get left edge mask
mov si,bx ; get right clip mask, save x2
and si,plane_bits ; mask out row #
and al,right_clip_mask[esi] ; get right edge mask byte
out_8 sc_data, al ; clip for left & right masks
mov al, colq ; get fill color
mov [edi], al ; fill in pixels
rf_exit:
pop eax ebp edi si ; pop screen left address
r_mis:
add edi, xactual/4
dec rise
jg r_lineloop
cl_return:
ret
; bubble sort for sides
; sort is not perfect since many sides can use the same point.
; if this point is the first point in the list and therefore zeds[] uses
; the same point for sort, the routine may mess up when plotting at some
; acute angles. if you ever notice this, you are way too picky. you
; could fix this by adjusting the load_sides routine to search for the
; closest z point.
align 16
minusd equ offset zeds - offset order
sort_list:
movzx esi,showing
cmp si,1 ; if only one surface, exit
jbe qke
shl si,1 ; si = word
add esi,o order
align 16
nextcx:
sub esi,2 ; point to last word in order[] table
mov ebp,esi ; set order pointer
mov bx,w [esi] ; get order[si]
mov edi,esi
add edi,minusd
mov cx,w [edi] ; get zeds[si]
align 16
nextdx:
sub edi,2
sub ebp,2
cmp cx,w [edi] ; zeds is point from side, should be max z
jle s donothing
xchg cx,w [edi] ; don't flip entire side, just indexers to it
xchg bx,w [ebp]
donothing:
cmp ebp,o order ; check bp = 0
jne s nextdx
mov [esi + minusd],cx
mov [esi],bx
cmp esi,o order + 2
jne s nextcx
qke:
ret
; routine sets the "final" variables for perfect updvectors calculations
; this fixes the small (and i mean small) discrepancies when the raster count
; does not divide evenly into the objects rotational or linear count.
; eg lcount =1001, raster count = 10, object should move 1001 units but gets
; moved 100*10 (only moves 1000 units). this makes absolutly sure that an
; object moved to a location in si frames will actually get to that exact
; position! (regardless of machine speed or raster speed or number of objects
; on screen or whatever!).
; call this routine after setting new anglular or linear velocities. there is
; no need to call this routine if you are going to set a position or location
; but xxxfinal must be set if you are going to change the velocities. the
; variables xxxfinal[] are used by updvectors to set the final position/angle
; of an object after the counters lcount and acount have expired. if you know
; the final position/angle of your object, set these yourself. but if
; you only want to move the object and don't care where it will end up, call
; this routine and the final position/angle will be calculated for you.
; note: xxxfinal variables will only be used if the raster count does not
; divide evenly into the angle/linear count.
; routine calculates for object si.
set_finall:
movzx esi,si ; do this in case user is lazy...
movzx ecx,lcount[esi*2] ; final position = speed * time
mov eax,xadds[esi*4] ; xsfinal = xadds * lcount + position
imul ecx ; you get the idea right?
add eax,xs[esi*4]
mov xsfinal[esi*4],eax
mov eax,yadds[esi*4]
imul ecx
add eax,ys[esi*4]
mov ysfinal[esi*4],eax
mov eax,zadds[esi*4]
imul ecx
add eax,zs[esi*4]
mov zsfinal[esi*4],eax
ret
set_finala:
movzx esi,si ; do this in case user is lazy...
mov cx,acount[esi*2] ; final angle = angular velocity * time
mov ax,vxadds[esi*2] ; vxsfinal = vxadds * acount + angle
imul cx
add ax,vxs[esi*2]
mov vxsfinal[esi*2],ax
mov ax,vyadds[esi*2]
imul cx
add ax,vys[esi*2]
mov vysfinal[esi*2],ax
mov ax,vzadds[esi*2]
imul cx
add ax,vzs[esi*2]
mov vzsfinal[esi*2],ax
ret
align 16
; point object si at object di
point_it:
push esi edi
xchg si,di ; xchange so user doesn't get confused
push di
call calc_angles
pop di
movzx edi,di
mov vxs[edi*2],ax
mov vys[edi*2],bx
pop edi esi
ret
align 16
; point object si in direction it is moving
point_dir:
movzx esi,si
mov ebx,xadds[esi*4]
mov ecx,yadds[esi*4]
mov ebp,zadds[esi*4]
shl ebx,4 ; * whatever to get some decimal accuracy
shl ecx,4
shl ebp,4
align 16
; point object si at location ebx,ecx,ebp.
point_to:
mov di,si ; xchange so user doesn't get confused
movzx edi,di
push edi
sub ebx,xs[edi*4] ; get displacement of esi to edi
sub ecx,ys[edi*4]
sub ebp,zs[edi*4]
call calc_middle
pop esi
mov vxs[esi*2],ax
mov vys[esi*2],bx
ret
align 16
; set speed of object si to ebp*angle, then set lcount to di
; (move object in direction it is pointing)
;
; xadds= - cx * sy * ebp
;
; yadds= - sx * ebp
;
; zadds= cx * cy * ebp
set_speed:
movzx esi,si
mov lcount[esi*2],di
mov ax,vxs[esi*2]
neg ax
push ax
call cosign
mov ecx,eax ; cx = cos x
pop ax
call sign
neg eax
imul ebp ; set y speed
shrd eax,edx,14
mov yadds[esi*4],eax
mov ax,vys[esi*2]
neg ax
push ax
call cosign
mov edx,eax ; dx = cos y
pop ax
call sign
mov ebx,edx ; save because imul trashes dx
imul ecx ; ax = sy * cx
shrd eax,edx,14 ; shr eax,14 compensates for cos decimals
imul ebp
shrd eax,edx,14
neg eax
mov xadds[esi*4],eax
mov eax,ebx
imul ecx
shrd eax,edx,14
imul ebp
shrd eax,edx,14
mov zadds[esi*4],eax
ret
; point object si at location ebx,ecx,ebp, in di frames (di = time)
; this could also be used for the camera, but if you are going to
; point the camera at an object, call newfollow instead. newfollow
; allows for when the object is moving - newfollow will track the
; object as it moves and even if it accelerates!
point_time:
push di si di si ebp ecx ebx
call where_si ; find out where object will be in di frames
pop eax
sub ebx,eax ; get displacement of where it will be to where
neg ebx ; it should point
pop eax
sub ecx,eax
neg ecx
pop eax
sub ebp,eax
neg ebp
pop di si ; notice reverse order for calc_middle
call calc_middle
movzx ecx,bx
movzx ebx,ax
test bx,8000h ; test to invert for other direction
jne no_inv1
xor ecx,0ffff0000h ; xor goes the other way
no_inv1:
test cx,8000h
jne no_inv2
xor ecx,0ffff0000h
no_inv2:
pop si ; pop object number
pop di ; pop time
movzx esi,si
mov ax,vzadds[esi*2] ; figure out z (calc_middle wont)
imul di
add ax,vzs[esi*2]
movzx ebp,ax
test bp,8000h
jne no_inv3
neg ebp
no_inv3:
; add ebx,00010000h ; do this if you want more than one rotation
; add ecx,00020000h ; along a selected axis.
; add ebp,00030000h ; maybe put a ret here then call twist_si yourself
jmp twist_si ; twist object to this location in di frames!
nullpalette:
i=0
rept 256
db i
i=i+1
endm
set_xref_palette: ; set cross referencing palette for object si
movzx esi,si
mov palxref[esi*4],ebx
ret